package com.longling.hayarider.utils;

import android.os.Handler;
import android.os.Looper;
import android.util.Log;

import com.google.gson.Gson;
import com.google.gson.JsonParseException;
import com.longling.hayarider.callback.OKHttpCallBack;
import com.longling.hayarider.callback.OkHttpDownLoadCallback;
import com.longling.hayarider.entity.BaseEntity;

import org.jetbrains.annotations.NotNull;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.CookieJar;
import okhttp3.FormBody;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * @ClassName RequrestUtil
 * @Description TODO OkHttp封装
 * @date 2021-07-08 13:09
 * @Company LongLing
 * @Version 1.0
 * @Author 潇妙
 */
public class RequrestUtil {
    private final String TAG = this.getClass().getName();
    private static RequrestUtil mInstance;
    private static OkHttpClient mOkHttpClient;
    private Gson mGson;
    private Handler mHander;

    public RequrestUtil(){
        mOkHttpClient = new OkHttpClient().newBuilder()
                .connectTimeout(60, TimeUnit.SECONDS)
                .writeTimeout(10,TimeUnit.SECONDS)
                .readTimeout(30,TimeUnit.SECONDS)
                .cookieJar(CookieJar.NO_COOKIES)
                .build();
        mHander = new Handler(Looper.getMainLooper());
    }

    public static RequrestUtil getInstance() {
        if (mInstance == null) {
            synchronized (RequrestUtil.class) {
                if (mInstance == null) {
                    mInstance = new RequrestUtil();
                }
            }
        }
        return mInstance;
    }

    /**
     * 异步get请求
     * @param url
     * @param callback
     * @param tag
     */
    public void getAsyn(String url, Map<String,String> params, final OKHttpCallBack callback, Object tag){
        Request request = new Request.Builder()
                .url(url)
                .get()
                .tag(tag)
                .build();
        deliveryResult(callback,request);
    }

    /**
     * 通用基础的异步的post请求
     * @param url
     * @param params
     * @param callBack
     * @param tag
     */
    public void postAsyn(String url, Map<String,String> params, final OKHttpCallBack callBack, Object tag){
        Request request= buildPostRequest(url,params,null,null,tag);
        deliveryResult(callBack,request);
    }

    /**
     * 请求参数表单创建(请求参数转为json字符串，字段名为data)
     * @param url
     * @param params
     * @param headkey
     * @param headValue
     * @param tag
     * @return
     */
    private Request buildPostRequest(String url, Map<String, String> params, String headkey, String headValue, Object tag) {
        FormBody.Builder builder = new FormBody.Builder();
        if (params!=null){
            Iterator<String> iterator = params.keySet().iterator();
            String key ="";
            while (iterator.hasNext()){
                key = iterator.next();
                builder.add(key,params.get(key));
            }
            String data =mGson.toJson(params);
            Log.i(TAG,"url:" + url + "\n requestParams:\n" + data);
        }
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.url(url)
                .post(builder.build())
                .tag(tag);
        requestBuilder.addHeader("token","");
        return requestBuilder.build();
    }

    /**
     * 传参下载文件
     * @param url
     * @param params
     * @param fileDir
     * @param fileName
     * @param callBack
     * @param tag
     */
    public void postAsynDownload(String url,Map<String,String> params,String fileDir,String fileName,final OkHttpDownLoadCallback callBack,Object tag){
        Request request = buildPostRequest(url,params,null,null,tag);
        downloadResult(fileDir,fileName,callBack,request);
    }

    /**
     * 不传参get下载文件
     * @param url
     * @param fileDir
     * @param fileName
     * @param callback
     * @param tag
     */
    public void getAsynDownload(String url, String fileDir, String fileName, final OkHttpDownLoadCallback callback, Object tag) {
        Request request = new Request.Builder()
                .url(url)
                .build();
        downloadResult(fileDir,fileName, callback, request);
    }

    /**
     * 发送json请求
     * @param url
     * @param jsonParams
     * @param callback
     */
    public void postJsonAsyn(String url, String jsonParams, final OKHttpCallBack callback) {
        RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8")
                , jsonParams);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();
        deliveryResult(callback, request);
    }

    /**
     * 上传文件
     * @param url
     * @param pathName
     * @param fileName
     * @param callback
     */
    public void uploadFile(String url, String pathName, String fileName, OKHttpCallBack callback) {
        //判断文件类型
        MediaType MEDIA_TYPE = MediaType.parse(judgeType(pathName));
        //创建文件参数
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart(MEDIA_TYPE.type(), fileName, RequestBody.create(MEDIA_TYPE, new File(pathName)));
        //发出请求参数
        Request request = new Request.Builder()
//                .header("Authorization", "Client-ID " + "9199fdef135c122")
                .url(url)
                .post(builder.build())
                .build();
        deliveryResult(callback, request);
    }
    /**
     * 根据文件路径判断MediaType
     * @param path
     * @return
     */
    private static String judgeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }

    /**
     * 下载文件
     * @param destFileDir
     * @param destFileName
     * @param listener
     * @param request
     */
    public void downloadResult(final String destFileDir, final String destFileName, final OkHttpDownLoadCallback listener, final Request request) {

        //异步请求
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                // 下载失败监听回调
                listener.onDownloadFailed(e);
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {

                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;

                //储存下载文件的目录
                File dir = new File(destFileDir);
                if (!dir.exists()) {
                    dir.mkdirs();
                }
                File file = new File(dir, destFileName);

                try {

                    is = response.body().byteStream();
                    long total = response.body().contentLength();
                    Log.i(TAG,"file size:" + (total * 1.0f) / 1024 + " KB");
                    fos = new FileOutputStream(file);
                    long sum = 0;
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                        sum += len;
                        int progress = (int) (sum * 1.0f / total * 100);
                        //下载中更新进度条
                        listener.onDownloading(progress);
                    }
                    fos.flush();
                    //下载完成
                    listener.onDownloadSuccess(file);
                } catch (Exception e) {
                    listener.onDownloadFailed(e);
                    e.printStackTrace();
                }finally {
                    try {
                        if (is != null) {
                            is.close();
                        }
                        if (fos != null) {
                            fos.close();
                        }
                    } catch (IOException e) {

                    }
                }
            }
        });
    }

    /**
     * 请求回调处理方法并传递返回值
     * @param callback Map类型请求参数
     * @param request Request请求
     */
    private void deliveryResult(OKHttpCallBack callback, final Request request){
        if (callback == null)
            callback = DEFAULT_RESULT_CALLBACK;
        final OKHttpCallBack resCallback = callback;
        callback.onBefore(request);
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(@NotNull Call call, @NotNull IOException e) {
                sendFailedStringCallback(request,"",resCallback);
            }

            @Override
            public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                try {
                    final String responseMessage=response.message();
                    final String responseBody=response.body().toString();
                    if (resCallback.mType == String.class) {
                        sendSuccessResultCallback(responseBody, resCallback);
                    } else {
                        Object o = mGson.fromJson(responseBody, resCallback.mType);
                        sendSuccessResultCallback(o, resCallback);
                    }
                }catch (JsonParseException e){
                    sendFailedStringCallback(response.request(),"", resCallback);
                }
            }
        });
    }

    private final OKHttpCallBack DEFAULT_RESULT_CALLBACK = new OKHttpCallBack<String>(){

        @Override
        public void onSuccess(String response) {

        }

        @Override
        public void onFailure(BaseEntity<String> entity, String message) {

        }
    };

    /**
     * 处理成功的回调方法
     * @param object
     * @param callBack
     */
    private void sendSuccessResultCallback(final Object object,final OKHttpCallBack callBack){
        mHander.post(new Runnable() {
            @Override
            public void run() {
                callBack.onSuccess(object);
                callBack.onAfter();
            }
        });
    }

    /**
     * 处理失败的回调方法
     * @param request
     * @param message
     * @param callback
     */
    private void sendFailedStringCallback(final Request request, final String message, final OKHttpCallBack callback){
        mHander.post(new Runnable() {
            @Override
            public void run() {
                callback.onFailure(null,message);

            }
        });
    }

    public void cancelAll(){
        if(mOkHttpClient ==null) return;
        for (Call call :mOkHttpClient.dispatcher().queuedCalls()){
            call.cancel();
        }
        for (Call call :mOkHttpClient.dispatcher().runningCalls()){
            call.cancel();
        }
    }

    public void cancelTag(Object tag){
        if (tag ==null) return;
        for (Call call :mOkHttpClient.dispatcher().queuedCalls()){
            if (tag.equals(call.request().tag())){
                call.cancel();
            }
        }
        for (Call call : mOkHttpClient.dispatcher().runningCalls()){
            if (tag.equals(call.request().tag())){
                call.cancel();
            }
        }
    }
}
